route.ts 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import { NextRequest, NextResponse } from "next/server";
  2. import { STORAGE_KEY } from "../../../constant";
  3. async function handle(
  4. req: NextRequest,
  5. { params }: { params: { path: string[] } },
  6. ) {
  7. if (req.method === "OPTIONS") {
  8. return NextResponse.json({ body: "OK" }, { status: 200 });
  9. }
  10. const folder = STORAGE_KEY;
  11. const fileName = `${folder}/backup.json`;
  12. const requestUrl = new URL(req.url);
  13. let endpoint = requestUrl.searchParams.get("endpoint");
  14. // Validate the endpoint to prevent potential SSRF attacks
  15. if (!endpoint || !endpoint.startsWith("/")) {
  16. return NextResponse.json(
  17. {
  18. error: true,
  19. msg: "Invalid endpoint",
  20. },
  21. {
  22. status: 400,
  23. },
  24. );
  25. }
  26. const endpointPath = params.path.join("/");
  27. const targetPath = `${endpoint}/${endpointPath}`;
  28. // only allow MKCOL, GET, PUT
  29. if (req.method !== "MKCOL" && req.method !== "GET" && req.method !== "PUT") {
  30. return NextResponse.json(
  31. {
  32. error: true,
  33. msg: "you are not allowed to request " + targetPath,
  34. },
  35. {
  36. status: 403,
  37. },
  38. );
  39. }
  40. // for MKCOL request, only allow request ${folder}
  41. if (
  42. req.method === "MKCOL" &&
  43. !targetPath.endsWith(folder)
  44. ) {
  45. return NextResponse.json(
  46. {
  47. error: true,
  48. msg: "you are not allowed to request " + targetPath,
  49. },
  50. {
  51. status: 403,
  52. },
  53. );
  54. }
  55. // for GET request, only allow request ending with fileName
  56. if (
  57. req.method === "GET" &&
  58. !targetPath.endsWith(fileName)
  59. ) {
  60. return NextResponse.json(
  61. {
  62. error: true,
  63. msg: "you are not allowed to request " + targetPath,
  64. },
  65. {
  66. status: 403,
  67. },
  68. );
  69. }
  70. // for PUT request, only allow request ending with fileName
  71. if (
  72. req.method === "PUT" &&
  73. !targetPath.endsWith(fileName)
  74. ) {
  75. return NextResponse.json(
  76. {
  77. error: true,
  78. msg: "you are not allowed to request " + targetPath,
  79. },
  80. {
  81. status: 403,
  82. },
  83. );
  84. }
  85. const targetUrl = `${endpoint}/${endpointPath}`;
  86. const method = req.method;
  87. const shouldNotHaveBody = ["get", "head"].includes(
  88. method?.toLowerCase() ?? "",
  89. );
  90. const fetchOptions: RequestInit = {
  91. headers: {
  92. authorization: req.headers.get("authorization") ?? "",
  93. },
  94. body: shouldNotHaveBody ? null : req.body,
  95. method,
  96. // @ts-ignore
  97. duplex: "half",
  98. };
  99. const fetchResult = await fetch(targetUrl, fetchOptions);
  100. console.log("[Any Proxy]", targetUrl, {
  101. status: fetchResult.status,
  102. statusText: fetchResult.statusText,
  103. });
  104. return fetchResult;
  105. }
  106. export const POST = handle;
  107. export const GET = handle;
  108. export const OPTIONS = handle;
  109. export const runtime = "edge";